package org.gongliang.jsmile.common.aop;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.gongliang.jsmile.authc.sys.entity.SysLog;
import org.gongliang.jsmile.common.enums.SF;
import org.gongliang.jsmile.common.kit.JsonKit;
import org.gongliang.jsmile.common.kit.StrKit;
import org.gongliang.jsmile.common.kit.web.ShiroKit;
import org.gongliang.jsmile.common.kit.web.UserAgentKit;
import org.gongliang.jsmile.common.kit.web.WebKit;
import org.gongliang.jsmile.config.log.info.KLog;
import org.gongliang.jsmile.config.log.info.LogType;
import org.gongliang.jsmile.config.log.task.TaskLog;
import org.gongliang.jsmile.config.shiro.web.ShiroUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.annotation.Order;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;

/**
 * 业务日志的记录
 *
 * @author 龚亮
 * @date 2016年12月6日 下午8:48:30
 */
@Aspect
@Order(-1)
public class LogKit {

	private static final Logger logger = LoggerFactory.getLogger(LogKit.class);
	
	@Around("within(org.gongliang.jsmile..*) && @annotation(klog)")
	public Object recordSysLog(ProceedingJoinPoint point, KLog klog) throws Throwable {

		// 先执行业务
		long beginTime = System.currentTimeMillis();
		Object result = point.proceed();
		long endTime = System.currentTimeMillis();
		SysLog log = new SysLog();
		log.setTimeConsuming((endTime - beginTime) + "");
		log.setIsOk(SF.S.getValue());
		try {
			String class_name = point.getTarget().getClass().getName();
			String method_name = point.getSignature().getName();
			Object[] args = point.getArgs();// 参数
			Map<String, Object> nameAndArgs = getFieldsName(class_name, method_name, args);// 获取被切参数名称及参数值
			if (!nameAndArgs.isEmpty()) {
				log.setReqParam(JsonKit.toJSONString(nameAndArgs));
			}
			if (klog.type() != LogType.QUERY) {
				log.setResParam(JsonKit.toJSONString(result));
			}
			handle(log, klog);
		} catch (Exception e) {
			logger.error("日志记录发生异常:" + ExceptionUtils.getStackTrace(e));
		}
		return result;
	}

	public static void handle(SysLog log, KLog klog) throws Exception {
		ShiroUser user = ShiroKit.getLoginUser();
		HttpServletRequest request = WebKit.getRequest();
		log.setIp(WebKit.getIpAddr(request));
		log.setCreateDate(new java.util.Date());
		if (user != null) {
			log.setCreator(user.getId());
			log.setUserName(user.getUserName());
		}
		log.setLogType(klog.type().name());
		log.setSystemId(klog.systemId());
		log.setBrowser(UserAgentKit.getUserBrowser(request));
		log.setOs(UserAgentKit.getUserOs(request));
		log.setBrowserVersion(UserAgentKit.getUserBrowserVersion(request));
		log.setReqUrl(request.getRequestURI());
		Map<String, Object> reqParams = WebKit.getParams(request);
		if (StrKit.isBlank(log.getReqParam())) {
			log.setReqParam(JsonKit.toJSONString(reqParams));
		}
		log.setReqMethod(request.getMethod());
		log.setTitle(klog.title());

		/*
		 * 日志记录
		 */
		TaskLog.getSingleton().add(log);
	}

	/**
	 * 通过反射机制 获取被切参数名以及参数值
	 *
	 * @param clazzName
	 * @param methodName
	 * @param args
	 * @return
	 * @throws Exception
	 */
	private Map<String, Object> getFieldsName(String class_name, String methodName, Object[] args) throws Exception {
		Map<String, Object> map = new HashMap<String, Object>();

		Class<?> clazz = Class.forName(class_name);
		LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
		Method[] methods = clazz.getDeclaredMethods();
		for (Method method : methods) {
			if (methodName.equals(method.getName())) {
				String[] params = u.getParameterNames(method);
				if (params != null && params.length > 0) {
					for (int i = 0; i < params.length; i++) {
						if (!(args[i] instanceof ServletRequest || args[i] instanceof ServletResponse
								|| args[i] instanceof HttpSession || args[i] instanceof ModelMap
								|| args[i] instanceof Model)) {
							map.put(params[i], args[i]);// paramNames即参数名
						}
					}
				}
			}
		}
		return map;
	}

}